// https://www.html5rocks.com/en/mobile/workingoffthegrid/#toc-appcache
// https://developer.mozilla.org/zh-CN/docs/Web/API/NavigatorOnLine/Online_and_offline_events

// 注册自定义事件
let fireEvent = function (name, data) {
  let e = document.createEvent('Event')
  e.initEvent(name, true, true)
  e.data = data
  window.dispatchEvent(e)
}
/**
 *网络检测
 * @param {*} params
 */
function Network(params = {}) {
  let timer,
    lastTimestamp = null,
    lastBytesLoaded = 0,
    measurements = [],
    downladAverage = 0,
    level = 0
  // url 是可选参数，如果指定了那么访问和指定地址的链接性
  let option = {
    url: 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js',
    timeout: 5000 // 超时时间
  }
  Object.assign(option, params)

  // 速度列表，最终计算10速度的平均值
  const updateMeasurements = function (speed) {
    if (measurements.length >= 10) {
      measurements.shift()
    }
    measurements.push(speed)
  }
  // 设置平均下载速度
  const setAverage = function () {
    let len = measurements.length
    if (!len) return
    // 如果没有数据说明文件太小，无法计算
    let total = measurements.reduce((t, c) => {
      return t + c
    })
    let av = total / len
    downladAverage = Math.round(av / 1024)
    if (downladAverage > 10) {
      level = 5
    } else if (downladAverage > 8) {
      level = 4
    } else if (downladAverage > 6) {
      level = 3
    } else if (downladAverage > 4) {
      level = 2
    } else if (downladAverage > 0) {
      level = 1
    }
  }
  // 下载进程
  const downloadProgress = function (ev) {
    // byte
    let { loaded, timeStamp } = ev
    let timeInSeconds
    if (lastTimestamp !== null) {
      let chunkSizeInBits = (loaded - lastBytesLoaded) * 8
      let timestampDifference = timeStamp - lastTimestamp
      // Some browsers use timestamps with a higher resolution
      if (timeStamp.toString().length === 16) {
        timeInSeconds = Math.round(timestampDifference / 1000) / 1000
      } else {
        timeInSeconds = Math.round(timestampDifference) / 1000
      }
      // Don't use unrealistic measurements
      // 事件每隔50ms触发一次
      if (timeInSeconds < 0.42) return
      // byte/second
      let speed = chunkSizeInBits / timeInSeconds / 1024
      // 更新速度
      updateMeasurements(speed)
      setAverage()
    }
    lastBytesLoaded = loaded
    lastTimestamp = timeStamp
  }
  // 检查远程网络
  this.checkRemoteNetwork = function (params = {}) {
    // url 是可选参数，如果指定了那么访问和指定地址的链接性
    let option = {
      url: 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js',
      timeout: 5000
    }
    Object.assign(option, params)
    // promise
    return new Promise((resove, reject) => {
      if (!window.navigator.onLine) {
        console.warn('You seem to be offline.')
        reject({
          connected: false,
          speed: null,
          level: 0
        })
      }
      // ajax 请求
      let xhr = new XMLHttpRequest()
      xhr.timeout = option.timeout
      xhr.addEventListener('progress', downloadProgress, false)
      xhr.onreadystatechange = function () {
        // 状态为done才执行下面的步骤
        if (xhr.readyState != 4) {
          return
        }
        // 重置已加载数据
        lastBytesLoaded = 0
        // 成功
        if (xhr.status === 200) {
          resove({
            connected: true,
            speed: downladAverage,
            level: level
          })
        } else {
          // in other status we think network unuseable
          reject({
            connected: false,
            speed: null,
            level: 0
          })
          return
        }
      }
      xhr.open('GET', option.url + `?=` + Date.now())
      xhr.send()
    })
  }
  let that = this
  // 回调函数
  /* let _listenerCallback = function(ev) {
    let { type } = ev
    if (type === 'online') {
      fireEvent('connectionStatus', {
        isOnline: true
      })
    } else if (type === 'offline') {
      fireEvent('connectionStatus', {
        isOnline: false
      })
    }
  }
  // 监听本地网络状态
  const onLocalStatus = function() {
    window.addEventListener('online', _listenerCallback)
    window.addEventListener('offline', _listenerCallback)
  } */
  // 监听远程网络状态
  const onRemoteStatus = function () {
    function check() {
      that
        .checkRemoteNetwork(option)
        .then((res) => {
          fireEvent('connectionStatus', {
            ...res
          })
        })
        .catch((err) => {
          fireEvent('connectionStatus', {
            ...err
          })
        })
      return check
    }
    timer = setInterval(check(), option.timeout + 10)
  }

  // 绑定事件监听
  this.on = function (callback) {
    // onLocalStatus()
    onRemoteStatus()
    window.addEventListener('connectionStatus', callback)
  }

  // 移除事件监听
  this.off = function (callback) {
    if (typeof callback !== 'function') {
      console.error('Network: you have to pass in a function')
      return
    }
    // window.removeEventListener('online', _listenerCallback)
    // window.removeEventListener('offline', _listenerCallback)
    window.removeEventListener('connectionStatus', callback)
    clearTimeout(timer)
  }
}

export default Network
